package net.jdm.constraint.dependence;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import net.jdm.common.Alert;
import net.jdm.common.Alert.AlertLevel;
import net.jdm.common.Alert.DetailLevel;
import net.jdm.constraint.Constraint;
import net.jdm.domain.dependence.ContainerDependence;
import net.jdm.domain.entity.Node;
import net.jdm.domain.entity.Scope;

public class DependenceConstraint  implements Constraint{
	private DependencePrinter dependencePrinter;
	private final ViolationDependenciesFinder<ContainerDependence> violationDependenciesFinder = new ViolationDependenciesFinder<ContainerDependence>();
    private Alert alert=new Alert();
	public static final Map<String,DependenceConstraintType> TYPES_MAP=new HashMap<String,DependenceConstraintType>();
	public enum DependenceConstraintType{FROM_TO,ONLY_TO,ONLY_FROM,DENY};
	static{
		TYPES_MAP.put(DependenceConstraintType.FROM_TO.name(),DependenceConstraintType.FROM_TO);
		TYPES_MAP.put(DependenceConstraintType.ONLY_TO.name(),DependenceConstraintType.ONLY_TO);
		TYPES_MAP.put(DependenceConstraintType.ONLY_FROM.name(),DependenceConstraintType.ONLY_FROM);
		TYPES_MAP.put(DependenceConstraintType.DENY.name(),DependenceConstraintType.DENY);
	}
	private Set<DependenceDefine> definedDependences=new HashSet<DependenceDefine>();
	private DependenceConstraintType dependenceConstraintType;
	public boolean check(Scope scope) {
   		Set<? extends ContainerDependence> violationDependences=this.violationDependenciesFinder.findViolationDependences(scope.getDependencesWithinMe(),getDefinedDependences(),getDependenceConstraintType());
    		if(!violationDependences.isEmpty()){
    			dependencePrinter.printViolationDependences(getAlert(),scope.getName(),getDependenceConstraintType(), getDefinedDependences(),violationDependences);
    			return false;
    		}
		return true;
	}
	public DependenceConstraint(DependenceConstraintType dependenceConstraintType) {
		this.dependenceConstraintType=dependenceConstraintType;
	}
	public void setDependenceConstraintType(DependenceConstraintType dependenceType) {
		this.dependenceConstraintType = dependenceType;
	}
	public DependenceConstraintType getDependenceConstraintType() {
		return this.dependenceConstraintType;
	}
	public Set<DependenceDefine> getDefinedDependences() {
		return this.definedDependences;
	}
	public void setDefinedDependences(Set<DependenceDefine> definedDependences) {
		this.definedDependences = definedDependences;
	}
	public void addDefinedDependence(DependenceDefine definedDependence){
		this.definedDependences.add(definedDependence);
	}

	public void deleteDefinedDependence(DependenceDefine dependenceConfig){
		this.definedDependences.remove(dependenceConfig);
	}
	@Override
	public void setAlertLevel(AlertLevel alertLevel) {
		alert.setAlertLevel(alertLevel);
	}
	@Override
	public void setDetailLevel(DetailLevel detailLevel) {
		this.alert.setDetailLevel(detailLevel);
	}
	@Override
	public void setAlertMessage(String alertMessage) {
		this.alert.setAlertMessage(alertMessage);
	}
	public Alert getAlert() {
		return alert;
	}
	public void addDefinedDependence(Node depender, Node depended) {
		addDefinedDependence(new DependenceDefine(depender.getName(),depended.getName()));
	}
	public void setPrinter(DependencePrinter dependencePrinter) {
		this.dependencePrinter = dependencePrinter;
	}
	public DependencePrinter getPrinter() {
		return dependencePrinter;
	}
}